#include <iostream>
#include <string>
#include <signal.h>

#include "sock.hpp"

void usage(std::string proc)
{
  std::cout << "usage:\n\t" << proc << ": need port" << std::endl;
}


int main(int argc, char* argv[])
{
  if (argc != 2)
  {
    usage(argv[0]);
    return 1;
  }

  uint16_t port = atoi(argv[1]);
  int listen_sock = Sock::Socket();
  Sock::Bind(listen_sock, port);
  //我们说一下back_log的作用
  //back_log + 1就是实际上TCP管理的建立正常的连接的个数
  //比如back_log = 1,那么实际上TCP管理的建立正确的连接的个数是2个
  //注意这里管理的正确的连接数是应用层没有accept()接收上去的连接数
  //我们以下面的这个例子为例
  int back_log = 1;
  Sock::Listen(listen_sock, back_log);

  //这里back_log = 1
  //我们启动4个client向server发起来TCP连接
  //但是我们最后发现server只有两个连接的状态是established
  //server还有两个连接的状是SYN_RECV
  //而client四个连接全部都是establised
  //当下面的accept,把获取到的全连接拿上来的时候
  //server就是三个established,一个SYN_RECV
  //accept再获取一个全连接,server四个连接也是established
  //这是因为, Linux内核协议栈为一个tcp连接管理使用两个队列:
  //1. 半链接队列（用来保存处于SYN_SENT和SYN_RECV状态的请求）
  //2. 全连接队列（accpetd队列）（用来保存处于established状态，但是应用层没有调用accept取走的请求）
  //而全连接队列的长度会受到 listen 第二个参数的影响.
  //全连接队列满了的时候, 就无法继续让当前连接的状态进入 established 状态了
  //半连接队列的长度是内核进行管理的,我们无法进行干预
  
  //Q:为什么全连接队列我们不能没有?
  //A:全连接队列提供了一个暂时存放全连接的地方
  //假设上层的应用层的负载为满(比如线程池满了),不能够再调用accpet(),拿到新的全连接
  //但是这个时候我们提供全连接的队伍,那么当一个线程任务执行完成了,那么就可以立刻拿到新的全连接
  //让线程马上就可以进行任务的执行,保证了线程池的资源是100%利用的
  //如果这个时候我们没有提供全连接的队伍,那么没有上层,就不能调用accpet(),拿到新的全连接
  //只有等新的TCP连接来了,才能拿到全连接,这个等待的时间,线程没有执行任务,没有充分的利用资源

  //Q:这个全连接队列为什么不能太长?
  //A:全连接队列太长,排在很后面的全连接因为迟迟没有被accpet()拿上去
  //所以会一直占用全连接队列的资源
  //所以我们不如让全连接队列平衡一点
  //将多余的资源提供给系统,让系统用资源去完成更加有意义的事情
  
  while(true)
  {
    sleep(20);
    int new_sock = Sock::Accept(listen_sock);
  }
  return 0;
}
